package com.sylli.oeuf.server.manager;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.red5.server.api.Red5;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sylli.oeuf.server.db.DatabaseProviderBundle;
import com.sylli.oeuf.server.exception.BasedException;
import com.sylli.oeuf.server.object.transferable.CharacterGeneralInfoTO;
import com.sylli.oeuf.server.object.transferable.CharacterPostDataTO;
import com.sylli.oeuf.server.object.transferable.WrappedCharacterInfoTO;

public class SessionManager {
	
	/*
	 * Concept:
	 * 
	 *  Bares in mind that session will be set or revoked only when
	 * the administrator tells them to. Thus, system doesn't care to the
	 * client-connect or disconnect events. Just verify if client still valid
	 * before service will be served to the client. 
	 */
	private static Logger log = LoggerFactory.getLogger( "manager.session" );
	
	private DatabaseProviderBundle providers = DatabaseProviderBundle.getInstance();
	
	private static Map<String, Integer> sessionCache = new HashMap<String, Integer>();
	
	private static SessionManager instance = null;
	
	public static SessionManager getInstance() {
		if (instance==null) {
			synchronized (SessionManager.class) {
				if (instance == null) {
					instance = new SessionManager();
				}
			}
		}
		return instance;
	}
	
	private SessionManager() {
		
	}
	
	public WrappedCharacterInfoTO getWrappedCharacterInfo() throws BasedException {
		return new WrappedCharacterInfoTO(
				getCharacterInfo(),
				getCharacterPostData());
	}
	
	public CharacterGeneralInfoTO getCharacterInfoFromCharacterName(String characterName) 
			throws BasedException {
		return providers.charGenInfo.get("name = '" + characterName + "'");
	}
	
	public CharacterGeneralInfoTO getCharacterInfo() throws BasedException {
		return providers.charGenInfo.get("char_id = " + getCharacterId());
	}
	
	public CharacterPostDataTO getCharacterPostData() throws BasedException {
		return providers.charPostData.get("char_id = " + getCharacterId());
	}
	
	public CharacterGeneralInfoTO getCharacterInfo(int character_id) throws BasedException {
		return providers.charGenInfo.get("char_id = " + character_id);
	}
	
	public void bind(Integer o) {
		synchronized (SessionManager.class) {
			// check single instance of Integer o
			if (sessionCache.containsValue(o)) {
				for (Entry<String, Integer> _entity : sessionCache.entrySet()) {
					if (_entity.getValue().equals(o)) {
						log.info("Removed " + _entity.getKey() + " from valid connection sessionCache.");
						sessionCache.remove(_entity.getKey());
					}
				}
			}
			sessionCache.put(Red5.getConnectionLocal().getClient().getId(), o);
		}
	}
	
	public void unbind() {
		synchronized (SessionManager.class) {
			sessionCache.remove(Red5.getConnectionLocal().getClient().getId());
		}
	}
	
	public int getCharacterId() {
		return sessionCache.get(Red5.getConnectionLocal().getClient().getId());
	}
}
